﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ComputerArchitecture.Numbers;
using ComputerArchitecture.Units.Interfaces;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

namespace ComputerArchitecture.Lab3
{
    class Program
    {
        #region Fields

        private readonly static IUnityContainer UnitsContainer = new UnityContainer().LoadConfiguration("units");

        #endregion

        static int Main(string[] args)
        {
            Console.WriteLine("Aleksey Suharev Divide bit number emulator @ 2013 p4s group");
            int size = -1;
            Func<string, ISignedBitNumber> createFirstOperand = null;
            Func<string, ISignedBitNumber> createSecondOperand = null;
            Func<ISignedBitNumber, string> getNormal = null;
            do
            {
                try
                {
                    Console.Write("Enter the size of operands: ");
                    string sizeString = Console.ReadLine();
                    if (ReferenceEquals(sizeString, null))
                    {
                        throw new ArgumentNullException("sizeString");
                    }
                    size = int.Parse(sizeString);
                    switch (size)
                    {
                        case 8:
                            createFirstOperand = s => short.Parse(s).CreateWordNumber();
                            createSecondOperand = s => sbyte.Parse(s).CreateByteNumber();
                            getNormal = b => b.ToByte().ToString();
                            break;
                        case 16:
                            createFirstOperand = s => int.Parse(s).CreateDoubleWordNumber();
                            createSecondOperand = s => short.Parse(s).CreateWordNumber();
                            getNormal = b => b.ToInt16().ToString();
                            break;
                        case 32:
                            createSecondOperand = s => int.Parse(s).CreateDoubleWordNumber();
                            createFirstOperand = s => long.Parse(s).CreateQuartedWordNumber();
                            getNormal = b => b.ToInt32().ToString();
                            break;
                        default:
                            throw new ArgumentException();
                    }
                }
                catch (FormatException)
                {
                    Console.WriteLine("Incorrect input! Try again.");
                    size = -1;
                }
                catch (ArgumentNullException)
                {
                    Console.WriteLine("Incorrect input! Try again.");
                    size = -1;
                }
                catch (ArgumentException)
                {
                    Console.WriteLine("Only 8, 16, 32 bits number supported!");
                    size = -1;
                }
                catch (Exception)
                {
                    Console.WriteLine("oops, something wrong!");
                    return -1;
                }
            } while (size == -1);
            if (ReferenceEquals(createFirstOperand, null))
            {
                throw new ArgumentNullException("Create first operand function is null");
            }
            if (ReferenceEquals(getNormal, null))
            {
                throw new ArgumentNullException("Create second operand function is null");
            }

            Console.Write("Enter first number (Note, that first number size is {0}*2): ", size);
            string firstNumberString = Console.ReadLine();
            ISignedBitNumber first = createFirstOperand(firstNumberString);
            Console.Write("Enter second number: ");
            string secondNumberString = Console.ReadLine();
            ISignedBitNumber second = createSecondOperand(secondNumberString);
            IDivideUnit divideUnit = UnitsContainer.Resolve<IDivideUnit>();
            ISignedBitNumber remainder, result;
            Console.WriteLine();
            try
            {
                result = divideUnit.Divide(first, second, out remainder);
            }
            catch (DivideByZeroException)
            {
                Console.Error.WriteLine("Divide by zero!");
                return 1;
            }
            Console.WriteLine("RESULT: {0:d4}; remainder: {1:d4} ({2}; remainder: {3})", result, remainder, getNormal(result), getNormal(remainder));
            return 0;
        }
    }
}
